//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using Microsoft.Practices.EnterpriseLibrary.Configuration.Design;

namespace EntLibContrib.Query.Configuration.Design
{
	/// <summary>
	/// This class builds the hierarchy node structure from an existing configuration
	/// to populate the console from configuration data.
	/// </summary>
	public class QuerySettingsNodeBuilder : NodeBuilder
	{
		#region Fields
		private QuerySettings querySettings;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new instance of the <see cref="QuerySettingsNodeBuilder"/> class.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="querySettings">The query settings.</param>
		public QuerySettingsNodeBuilder(IServiceProvider serviceProvider, QuerySettings querySettings)	: base(serviceProvider)
		{
			this.querySettings = querySettings;
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Builds this instance.
		/// </summary>
		/// <returns></returns>
		public QuerySettingsNode Build()
		{
			QuerySettingsNode rootNode = new QuerySettingsNode();

			// build the command nodes
			CommandCollectionNode commandCollectionNode = new CommandCollectionNode();
			foreach (CustomCommandData customCommandData in querySettings.Commands)
			{
				BuildCommandNode(commandCollectionNode, customCommandData);
			}
			rootNode.AddNode(commandCollectionNode);

			// build the parameter set nodes
			ParameterCollectionNode parameterCollectionNode = new ParameterCollectionNode();
			foreach (ParameterSetData parameterSetData in querySettings.ParameterSets)
			{
				BuildParameterSetNode(parameterCollectionNode, parameterSetData);
			}
			rootNode.AddNode(parameterCollectionNode);

			// build the query nodes
			QueryCollectionNode queryCollectionNode = new QueryCollectionNode();
			foreach (QueryDataBase queryData in querySettings.Queries)
			{
				ConfigurationNode queryNode = BuildQueryNode(queryCollectionNode, queryData);
				if (queryNode != null)
					ConfigureQueryNode(queryNode, parameterCollectionNode, commandCollectionNode);
			}
			rootNode.AddNode(queryCollectionNode);

			// set the require permission mode
			rootNode.RequirePermission = querySettings.SectionInformation.RequirePermission;
			return rootNode;
		}
		#endregion

		#region Private Methods
		private void BuildCommandNode(CommandCollectionNode commandCollectionNode, CustomCommandData customCommandData)
		{
			ConfigurationNode commandNode = NodeCreationService.CreateNodeByDataType(customCommandData.GetType(), new object[] { customCommandData });
			if (null == commandNode)
			{
				LogNodeMapError(commandCollectionNode, customCommandData.GetType());
				return;
			}

			commandCollectionNode.AddNode(commandNode);
		}

		private void BuildParameterSetNode(ParameterCollectionNode parameterCollectionNode, ParameterSetData parameterSetData)
		{
			ConfigurationNode parameterSetNode = NodeCreationService.CreateNodeByDataType(parameterSetData.GetType(), new object[] { parameterSetData });
			if (null == parameterSetNode)
			{
				LogNodeMapError(parameterCollectionNode, parameterSetData.GetType());
				return;
			}

			foreach (ParameterData parameterData in parameterSetData.Parameters)
			{
				BuildParameterNode(parameterSetNode, parameterData);
			}

			parameterCollectionNode.AddNode(parameterSetNode);
		}

		private void BuildParameterNode(ConfigurationNode node, ParameterData parameterData)
		{
			ConfigurationNode parameterNode = NodeCreationService.CreateNodeByDataType(parameterData.GetType(), new object[] { parameterData });
			if (null == parameterNode)
			{
				LogNodeMapError(node, parameterNode.GetType());
				return;
			}
			node.AddNode(parameterNode);
		}

		private ConfigurationNode BuildQueryNode(QueryCollectionNode queryCollectionNode, QueryDataBase queryData)
		{
			ConfigurationNode queryNode = NodeCreationService.CreateNodeByDataType(queryData.GetType(), new object[] { queryData });
			if (null == queryNode)
			{
				LogNodeMapError(queryCollectionNode, queryData.GetType());
				return null;
			}

			queryCollectionNode.AddNode(queryNode);
			return queryNode;
		}

		private static void ConfigureQueryNode(ConfigurationNode node,
																					ParameterCollectionNode parameterCollectionNode,
																					CommandCollectionNode commandCollectionNode)
		{
			QueryNode queryNode = node as QueryNode;
			if (queryNode != null)
			{
				foreach (ConfigurationNode configurationNode in parameterCollectionNode.Nodes)
				{
					if (configurationNode.Name == queryNode.ParameterSetName)
					{
						ParameterSetNode parameterSetNode = configurationNode as ParameterSetNode;
						if (parameterSetNode != null)
							queryNode.ParameterSet = parameterSetNode;
						break;
					}
				}

				foreach (ConfigurationNode configurationNode in commandCollectionNode.Nodes)
				{
					if (configurationNode.Name == queryNode.CustomCommandName)
					{
						CommandNode commandNode = configurationNode as CommandNode;
						if (commandNode != null)
							queryNode.CustomCommand = commandNode;
						break;
					}
				}
			}
		}
		#endregion
	}
}